#include <asm/regdef.h>
//#include <asm/cp0regdef.h>
#include <asm/asm.h>
#include <stackframe.h>
#include <unistd.h>

/*** exercise 4.2 ***/
.text
NESTED(handle_sys,TF_SIZE, sp)
	// Fetch EPC from Trapframe, calculate a proper value and store it back to trapframe.
	ld	t0, TF_EPC(sp)
	addi	t0, t0, 4
	sd	t0, TF_EPC(sp)
	// Copy the syscall number into $a0.
	ld	a0, TF_REG10(sp)
	ld	a1, TF_REG11(sp)
	ld	a2, TF_REG12(sp)
	ld	a3, TF_REG13(sp)
	ld	a4, TF_REG14(sp)
	ld	a5, TF_REG15(sp)
	li	t0, -__SYSCALL_BASE
	add	a0, a0, t0		// a0 <- relative syscall number
	sll	t0, a0, 3                   // t0 <- relative syscall number times 4
	la	t1, sys_call_table          // t1 <- syscall table base
	add	t1, t1, t0                  // t1 <- table entry of specific syscall
	ld	t2, 0(t1)                   // t2 <- function entry of specific syscall

//	ld	t0, TF_REG2(sp)            // t0 <- user's stack pointer
//	ld	a4, 32(t0)                  // t3 <- the 5th argument of msyscall
//	ld	a5, 40(t0)                  // t4 <- the 6th argument of msyscall
	addi	sp, sp, -48
	sd	a5, 40(sp)
	sd	a4, 32(sp)
	sd	a3, 24(sp)
	sd	a2, 16(sp)
	sd	a1, 8(sp)
	sd	a0, 0(sp)
	jalr	t2
	addi	sp, sp, 48
	sw	a0, TF_REG10(sp)
	call	ret_from_exception
/*
    SAVE_ALL                            // Macro used to save trapframe
    CLI                                 // Clean Interrupt Mask
    nop
    .set at                             // Resume use of $at

    // TODO: Fetch EPC from Trapframe, calculate a proper value and store it back to trapframe.
    lw      t0, TF_EPC(sp)
    addiu   t0, t0, 4
    sw      t0, TF_EPC(sp)
    // TODO: Copy the syscall number into $a0.
    lw      a0, TF_REG4(sp)
    addiu   a0, a0, -__SYSCALL_BASE     // a0 <- relative syscall number
    sll     t0, a0, 2                   // t0 <- relative syscall number times 4
    la      t1, sys_call_table          // t1 <- syscall table base
    addu    t1, t1, t0                  // t1 <- table entry of specific syscall
    lw      t2, 0(t1)                   // t2 <- function entry of specific syscall

    lw      t0, TF_REG29(sp)            // t0 <- user's stack pointer
    lw      t3, 16(t0)                  // t3 <- the 5th argument of msyscall
    lw      t4, 20(t0)                  // t4 <- the 6th argument of msyscall

    // TODO: Allocate a space of six arguments on current kernel stack and copy the six arguments to proper location
//    lw      a0, TF_REG4(sp)
//    lw      a1, TF_REG5(sp)
//    lw      a2, TF_REG6(sp)
//    lw      a3, TF_REG7(sp)
    addiu   sp, sp, -24
    sw      t4, 20(sp)
    sw      t3, 16(sp)
    sw      a3, 12(sp)
    sw      a2, 8(sp)
    sw      a1, 4(sp)
    sw      a0, 0(sp)
//DEBUG
//bnez t2, DEBUG_RETURN_1
//nop
//j DEBUG_TEST1
//nop
//DEBUG_RETURN_1:

    jalr    t2                          // Invoke sys_* function
    nop
    // TODO: Resume current kernel stack
    addiu   sp, sp, 24
    sw      v0, TF_REG2(sp)             // Store return value of function sys_* (in $v0) into trapframe

    j       ret_from_exception          // Return from exeception
    nop*/
END(handle_sys)

.globl	sys_call_table
.align 3
sys_call_table:                         // Syscall Table
	.quad sys_putchar
	.quad sys_getenvid
	.quad sys_yield
//	.quad sys_putchar // for testing
	.quad sys_env_destroy
	.quad sys_set_pgfault_handler
	.quad sys_mem_alloc
	.quad sys_mem_map
	.quad sys_mem_unmap
	.quad sys_env_alloc
	.quad sys_set_env_status
	.quad sys_set_trapframe
	.quad sys_panic
	.quad sys_ipc_can_send
	.quad sys_ipc_recv
	.quad sys_cgetc
